import _merge from 'lodash/merge'
import { Toast } from 'vant'
import AppConfig from '@/config'
import Token from '@/service/token'
import asyncRouter from '@/service/router/async'
import httpInstance from './http-instance'
import RequestCancel from './request-cancel'
import RequestCache from './request-cache'
import { findApi } from '../config'

const requestCancel = new RequestCancel()
const requestCache = new RequestCache()

// 路由变化时取消所有请求
asyncRouter.registerRouteEvent('beforeEach', (to, from, next) => {
  if (to.path !== from.path) {
    requestCancel.cancel({
      message: 'Cancel all requests when routing changes',
      hidden: true
    })
  }
  next()
})

async function httpDispatch (name, config) {
  // 请求配置
  const httpConfig = await getHttpConfig(name, config)

  // 使用缓存
  if (httpConfig._useCache) {
    const _cache = requestCache.get(httpConfig)
    if (_cache) return _cache.request
  }

  // 创建请求
  const httpRequest = getHttpRequest(httpConfig)

  // 添加缓存
  if (httpConfig._useCache) requestCache.add(httpConfig, httpRequest)

  return httpRequest
}

async function getHttpConfig (name, query) {
  // api 配置
  const apiConfig = findApi(name)
  if (!apiConfig) throw new Error(`httpDispatch 没有找到对应的请求配置; name: ${name}`)

  // 请求配置
  const httpConfig = _merge({
    headers: {
      'Content-Type': 'application/json'
    }
  }, apiConfig.config, query || {})

  // 添加 accessToken
  httpConfig.headers.accessToken = await Token.getToken()

  // 添加 cancelToken
  if (!httpConfig.cancelToken && !httpConfig._noCancel) {
    httpConfig.cancelToken = requestCancel.token
  }

  // url 处理
  httpConfig.url = AppConfig['host'] ? AppConfig['host'] + httpConfig.url : httpConfig.url

  return httpConfig
}

async function getHttpRequest(config) {
  let extend = function (dst) {
    for (let i = 1, ii = arguments.length; i < ii; i++) {
      let obj = arguments[i];
      if (obj) {
        let keys = Object.keys(obj);
        for (let j = 0, jj = keys.length; j < jj; j++) {
          let key = keys[j];
          dst[key] = obj[key];
        }
      }
    }
    return dst;
  };
  if (config.method === 'post_formdata') {
    let fd = new FormData();
    for (let i in config.data) {
      fd.append(i, config.data[i]);
    }
    let reqData = {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      data: fd,
      method: 'post'
    };
    // 添加 accessToken
    reqData.headers.accessToken = await Token.getToken()
    config = extend(config, reqData);
  }

  return httpInstance(config).then(response => {
    const data = response
    // 平台接口数据格式处理
    if (data && data.status === 200 && data.data.code === 0) return data.data

    // 接口数据异常处理
    const message = data && (data.msg || data.message)
    // 抛出异常数据
    throw Object.assign(data, { message })
  }).catch(error => {
    // 提示服务器异常信息
    if (config._showMessage || config._showMessage === undefined) {
      // 如果设置了 message.hidden 则不提示
      if (!(error.message && error.message.hidden)) {
        const message = error.message || error.msg
        setTimeout(() => Toast.fail(message || '服务器异常'), 100)
      }
    }
    throw error
  })
}

export default httpDispatch
export {
  requestCancel,
  requestCache
}
